﻿using Behavioral.Private;
using NUnit.Framework;

namespace Behavioral.Tests
{
    [TestFixture]
    public class ContextTests : IContextGetter
    {
        #region DynamicContextIsSettableInInitializer

        [Test]
        public void DynamicContextIsSettableInInitializer()
        {
            TestClass1 testClass = new TestClass1();

            testClass.Run();

            Assert.AreEqual("Hello World!", this.Context().AnExampleContextValue);
        }

        class TestClass1 : UnitTest<int>
        {
            public void Run()
            {
                GivenThat<AnInitializerIsCalledThatWritesDynamicContext>()
                .When<NoOpAction>();
            }
        }

        class AnInitializerIsCalledThatWritesDynamicContext : IInitializer<int>
        {
            public void SetUp(ref int param)
            {
                this.Context().AnExampleContextValue = "Hello World!";
            }
        }

        class NoOpAction : IAction<int>
        {
            public void Execute(int param)
            {
                
            }
        }

        #endregion

        #region ValidNamedTypedContextCanBeRetrievedViaDynamicContext

        [Test]
        public void ValidNamedTypedContextCanBeRetrievedViaDynamicContext()
        {
            TestClass2 testClass = new TestClass2();

            testClass.Run();

            Assert.AreEqual(365, this.Context().AnotherExampleOfUsingDynamicContext);
        }

        class TestClass2 : UnitTest<int>
        {
            public void Run()
            {
                GivenThat<AnInitializerIsCalledThatUsesNamedTypedContext>()
                .When<NoOpAction>();
            }
        }

        class AnInitializerIsCalledThatUsesNamedTypedContext : IInitializer<int>
        {
            public void SetUp(ref int target)
            {
                this.SetContext("AnotherExampleOfUsingDynamicContext", 365);
            }
        }

        #endregion

        #region InitializersCanReadDynamicContextThatWasSetFluently

        [Test]
        public void InitializersCanReadDynamicContextThatWasSetFluently()
        {
            var testClass = new TestInitializerWithFluentDynamicContext();
            testClass.SetUpInitializerWithFluentDynamicContext();
            Assert.AreEqual(365, AnInitializerIsCalledThatReadsDynamicContext.ContextValue);
            Assert.AreEqual(365, this.Context().SomeKindOfContextualValue);
        }

        class TestInitializerWithFluentDynamicContext : UnitTest<int>
        {
            public void SetUpInitializerWithFluentDynamicContext()
            {
                GivenThat<AnInitializerIsCalledThatReadsDynamicContext>()
                    .WithContext(c => c.SomeKindOfContextualValue = 365)
                .When<NoOpAction>();
            }
        }

        class AnInitializerIsCalledThatReadsDynamicContext : IInitializer<int>
        {
            public static int ContextValue;
            public void SetUp(ref int target)
            {
                ContextValue = this.Context().SomeKindOfContextualValue;
            }
        }

        #endregion

        #region AccessingContextThatHasNotBeenSetReturnsTheDefaultValue

        [Test]
        public void AccessingContextThatHasNotBeenSetReturnsNull()
        {
            Assert.AreEqual(null, this.Context().SomeKindOfValue);
        }

        #endregion
    }

    [TestFixture]
    public class NamedContextTests : IContextGetter, IContextSetter
    {
        [Test]
        public void NamedContextShouldBeDistinct()
        {
            int one = 1;
            int two = 2;
            int three = 3;

            this.SetContext("One", one);
            this.SetContext("Two", two);
            this.SetContext(three);

            Assert.That(this.GetContext<int>("One"), Is.EqualTo(1));
            Assert.That(this.GetContext<int>("Two"), Is.EqualTo(2));
            Assert.That(this.GetContext<int>(), Is.EqualTo(3));
        }
    }
}

